package com.tool.cn.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.math.BigInteger;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.zip.CRC32;

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 读写文件
 * 
 * @author wangzh 2016年9月19日 上午11:46:20
 */
public final class FileUtil {

	private static final Logger log = LoggerFactory.getLogger(FileUtil.class);

	public static String newLine = System.getProperty("line.separator");
	
	/**
	 * linux 目录分隔符
	 */
	public static String linuxSeparator="/"; 

	/**
	 * 400M 文件大小
	 */
	public static int fileSize=400*1024*1024;
	
	/**
	 * 拆分文件 400M一个子文件
	 * @param file 源文件
	 * @return
	 */
	public static int splitFile(String file) {
		int size=1;
		File tmpFile=new File(file+"-"+size);
		String context;
		BufferedWriter write=null;
		try (BufferedReader red=new BufferedReader(new InputStreamReader(new FileInputStream(file),"utf-8"))){
		
			write=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tmpFile,false),"utf-8"));
			while((context=red.readLine())!=null){
				write.write(context+System.getProperty("line.separator"));
				
				if(file.length()>=fileSize) {
					log.info("Split File:{}",tmpFile.toString());
					write.flush();
					write.close();
					
					size++;
					tmpFile=new File(file+"-"+size);
					write=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tmpFile,false),"utf-8"));
				}
			}
		} catch(Exception e) {
			log.error("Read File : "+file+" Error",e);
			return -1;
		}finally {
			if(write!=null) {
				try {
					write.flush();
					write.close();
				} catch (Exception e) {
					log.error("Close Write File IO Error",e);
				}
			}
		}
		return size;
	}
	
	/**
	 * Buffered 读取文件内容 非java8 nio方式
	 * @param file
	 * @return
	 */
	public static List<String> readFileList(String file){
		List<String> dataList=new ArrayList<>();
		String context;
		try(BufferedReader buf=new BufferedReader(new InputStreamReader(new FileInputStream(file),"utf-8"))){
			while((context=buf.readLine())!=null){
				if(StringUtil.isNotEmpty(context)) {
					dataList.add(context);
				}
			}
		}catch(Exception e) {
			log.error("Read File :"+file+" Error",e);
		}
		
		return dataList;
	}
	
	/**
	 * Linux获取程序目录
	 */
	public static String getPath(Class<?> classFormat) {
		String path = classFormat.getProtectionDomain().getCodeSource().getLocation().getPath();
		if (path.startsWith("file:")) {
			path = path.replace("file:", "");
		}

		if (System.getProperty("os.name").contains("dows")) {
			path = path.substring(1, path.length());
		}

		if (path.contains("jar")) {
			do {
				path = path.substring(0, path.lastIndexOf("."));
				path = path.substring(0, path.lastIndexOf("/"));
			} while (path.contains("jar"));

		}

		return new File(path.replace("/classes/", "")).getParent();
	}

	/**
	 * Linux获取程序目录
	 */
	public static String getPath() {
		return getPath(FileUtil.class);
	}
	
	/**
	 * 删除文件
	 * @param file
	 */
	public static boolean deleteFile(String file) {
		return deleteFile(new File(file));
	}
	
	/**
	 * 删除文件
	 * @param file
	 */
	public static boolean deleteFile(File file) {
		if(file.exists()) {
			return file.delete();
		}
		return true;
	}
	
	/**
	 * 获取文件内容行数 去除空行
	 * @param file
	 * @return
	 */
	public static int getFileNumNotNull(String file) {
		int line=0;
		String data;
		try(BufferedReader buf = new BufferedReader(new InputStreamReader(new FileInputStream(file)))){
			
			while((data = buf.readLine()) != null) {
				if(StringUtil.isNotEmpty(data)) {
					line++;
				}
			}
			
		}catch(Exception e) {
			log.error("Read File:"+file +" Num Error",e);
		}
		
		return line;
	}
	
	/**
	 * 获取文件内容行数 包括空行
	 * @param file
	 * @return
	 */
	public static int getFileNum(String file) {
		int line = 0;
        try {
                FileReader fr = new FileReader(new File(file));
                LineNumberReader lnr = new LineNumberReader(fr);
                lnr.skip(Long.MAX_VALUE);
                //因为是从0开始计数，所以需要+1
                line = lnr.getLineNumber() + 1;
                lnr.close();
        } catch (Exception e) {
        	log.error("Get File "+file+" Data Row Num Error "+e.toString(),e);
        }
        return line;
	}
	
	/**
	 * 零拷贝复制文件
	 * @param src 源文件
	 * @param dest 目标文件
	 * @return
	 */
	@Deprecated
	public static boolean zeroCopyFile(String src, String dest) {
		log.info("Copy File {} To File {} ",src,dest);
		try  {
				Files.copy( Paths.get(src),  Paths.get(dest), StandardCopyOption.REPLACE_EXISTING);
	            return true;
	        } catch (Exception e) {
	        	log.error("Copy File:"+src+" To "+dest+" Error "+e.toString(),e);
	        }
		return false;
	}
	
	/**
	 * 移动文件
	 * @param src 源文件
	 * @param dest 结果文件
	 * @return
	 */
	public static boolean moveFile(String src,String dest) {
		try {
			Files.move(Paths.get(src), Paths.get(dest), StandardCopyOption.REPLACE_EXISTING);
		} catch (Exception e) {
			log.error("Move File:"+src+" To "+dest+" Error",e);
			return false;
		}
		return true;
	}
	
	/**
	 * 清空文件
	 */
	public static boolean cleanFile(String file) {
		return writeData(file,"", false);
	}

	/**
	 * utf-8 编码文件写入内容
	 * @param file 文件路径
	 * @param content 内容集合
	 * @return
	 */
	public static boolean writeData(String file,List<String> content) {
		return writeData(file,content,true);
	}
	
	/**
	 * utf-8 编码文件写入内容
	 * @param file 文件路径
	 * @param content 内容集合
	 * @param state true追加 false 覆盖
	 * @return
	 */
	public static boolean writeData(String file,List<String> content,boolean state) {
		return writeData(file,content, state, StandardCharsets.UTF_8);
	}
	
	/**
	 * 文件写入内容
	 * @param file 文件
	 * @param content 内容集合
	 * @param state true追加 false 覆盖
	 * @param chartName 编码格式
	 * @return
	 */
	public static boolean writeData(String file,List<String> content,boolean state,Charset charset){
		try {
			if(!new File(file).exists()) {
				new File(file).createNewFile();
			}
			
			if(state) {
				Files.write(Paths.get(file), content,charset , StandardOpenOption.APPEND);
			}else {
				Files.write(Paths.get(file), content,charset , StandardOpenOption.TRUNCATE_EXISTING);
			}
			
			
			return true;
		} catch (Exception e) {
			log.error("File: "+file+" Write Error",e);
			return false;
		}
	}
	
	/**
	 * utf-8 编码文件写入内容
	 * @param file 文件路径
	 * @param content 内容
	 * @return
	 */
	public static boolean writeData(String file,String content) {
		return writeData(file, content, true);
	}
	
	/**
	 * utf-8 编码文件写入内容
	 * @param file 文件路径
	 * @param content 内容
	 * @param state true追加 false 覆盖
	 * @return
	 */
	public static boolean writeData(String file,String content,boolean state) {
		return writeData(file,content, state, "utf-8");
	}
	
	/**
	 * 文件写入内容
	 * @param file 文件
	 * @param content 内容
	 * @param state true追加 false 覆盖
	 * @param chartName 编码格式
	 * @return
	 */
	public static boolean writeData(String file,String content,boolean state,String chartName){
		try(BufferedWriter write=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file,state),chartName))) {
			if(StringUtil.isNotEmpty(content)) {
				write.write(content + System.getProperty("line.separator"));
			}else {
				write.write(content);
			}

			return true;
		} catch (Exception e) {
			log.error("File: "+file+" Write Error",e);
			return false;
		}
	}
	
	/**
	 * utf-8 按行提取文件内容
	 * @param file 文件路径
	 * @return
	 */
	public static List<String> readDataList(String file) {
		return readDataList(file, StandardCharsets.UTF_8);
	}
	
	/**
	 * 按行提取文件内容
	 * @param file 文件路径
	 * @param chartName 编码
	 * @return
	 */
	public static List<String> readDataList(String file,Charset charset){
		try{
			return  Files.readAllLines(Paths.get(file), charset);
		} catch (Exception e) {
			log.error("Read File: "+file+" Error",e);
		}
		return new ArrayList<>();
	}
	
	/**
	 * utf-8提取文件内容
	 * @param file 文件
	 * @return
	 */
	public static String readDataString(String file){
		return readDataString(file, "utf-8");
	}
	
	/**
	 * 读取文件返回二进制文件
	 * @param filename
	 * @return
	 */
	public static byte[] readFileToByte(File filename) {
		ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
		try(BufferedInputStream in = new BufferedInputStream(new FileInputStream(filename))){
			  byte[] temp = new byte[1024];
			    int size = 0;
			    while((size = in.read(temp)) != -1){
			        out.write(temp, 0, size);
			    }
		}catch(Exception e) {
			e.printStackTrace();
		}
	  
	    byte[] content = out.toByteArray();
	    return content;
	}
	
	/**
	 * 提取文件内容
	 * @param file 文件路径
	 * @param chartName 编码
	 * @return
	 */
	public static String readDataString(String file,String chartName){
		try{
			return new String(Files.readAllBytes(Paths.get(file)),chartName);
		} catch (Exception e) {
			log.error("Read File: "+file+" Error",e);
		}
		return "";
	}

	/**
	 * 清空目录下文件夹和文件
	 * @param path
	 * @return
	 */
	public static boolean deleteChildDir(String path) {
		return deleteDir(new File(path), new File(path), false);
	}
	
	/**
	 * 删除当前目录
	 * @param path
	 * @return
	 */
	public static boolean deleteDir(String path) {
		return deleteDir(new File(path), new File(path), true);
	}
	
	/**
	 * 递归删除目录下的所有文件及子目录下所有文件
	 * 
	 * @param dir 将要删除的文件目录
	 * @param state 是否删除当前目录
	 */
	private static boolean deleteDir(File rootdir,File dir,boolean state) {
		if (dir.isDirectory()) {
			String[] children = dir.list();
			// 递归删除目录中的子目录下
			for (int i = 0; i < children.length; i++) {
				boolean success = deleteDir(rootdir,new File(dir, children[i]),state);
				if (!success) {
					return false;
				}
			}
		}
		// 目录此时为空，可以删除
		if(!state&&rootdir.getPath().equals(dir.getPath())) {
				return true;
		}
		return dir.delete();
	}

	/**
	 * 获取路径下文件，过滤.和~开头，tmp结尾文件
	 * 
	 * @param url
	 * @param param
	 * @return
	 */
	public static String[] getFile(String url) {
		File input = new File(url);
		String[] fileName = input.list(new FilenameFilter() {
			@Override
			public boolean accept(File paramFile, String paramString) {
				System.out.println(paramString);

				if (paramString.startsWith(".") || paramString.endsWith("~") || paramString.endsWith("tmp")) {
					return false;
				}
				return true;
			}
		});

		return fileName;
	}

	/**
	 * 获取文件名，不包含后缀
	 * 
	 * @param file
	 * @return
	 */
	public static String getName(File file) {
		String name = file.getName();
		int num = name.lastIndexOf(".");
		name = name.substring(0, num);
		return name;
	}

	/**
	 * 获取文件后缀，包含点
	 * 
	 * @param file
	 * @return
	 */
	public static String getFileType(File file) {
		String name = file.getName();
		int num = name.lastIndexOf(".");
		String fileType = name.substring(num);
		return fileType;
	}

	/**
	 * 对一个文件获取md5值
	 */
	public static String getMD5Three(String path) {
		File f = new File(path);
		
		try(FileInputStream fis = new FileInputStream(f)) {
			byte[] buffer = new byte[8192];
			int len = 0;
			MessageDigest md = MessageDigest.getInstance("MD5");
			
			while ((len = fis.read(buffer)) != -1) {
				md.update(buffer, 0, len);
			}

			byte[] b = md.digest();
			
			StringBuilder stringBuilder = new StringBuilder("");   
		    for (int i = 0; i < b.length; i++) {   
		        int v = b[i] & 0xFF;   
		        String hv = Integer.toHexString(v);   
		        if (hv.length() < 2) {   
		            stringBuilder.append(0);   
		        }   
		        stringBuilder.append(hv);   
		    }   
		    
		    return stringBuilder.toString();
		} catch (Exception e) {
			log.error("Get File:"+path+" Value Of MD5 Error",e);
			return "";
		}
		
	}

	/***
	 * 计算SHA1码
	 * 
	 * @return String 适用于上G大的文件
	 * @throws NoSuchAlgorithmException
	 */
	public static String getSha1(File file) {

		BigInteger bi = null;
		MessageDigest messagedigest;
		try(FileChannel ch = new RandomAccessFile(file,"r").getChannel()) {
			messagedigest = MessageDigest.getInstance("SHA-1");
			MappedByteBuffer byteBuffer = ch.map(FileChannel.MapMode.READ_ONLY, 0, file.length());
			messagedigest.update(byteBuffer);

			byte[] b = messagedigest.digest();
			bi = new BigInteger(1, b);
			return bi.toString(16);
		} catch (Exception e) {
			log.error("Get File:"+file+" Value Of SHA-1 Error", e);
			return "";
		}
		
	}

	/**
	 * 获取文件CRC32码
	 * 
	 * @return String
	 */
	public static String getCRC32(File file) {
		CRC32 crc32 = new CRC32();
		try(FileInputStream fileInputStream = new FileInputStream(file)) {
			
			byte[] buffer = new byte[8192];
			int length;
			while ((length = fileInputStream.read(buffer)) != -1) {
				crc32.update(buffer, 0, length);
			}
			return crc32.getValue() + "";
		} catch (Exception e) {
			log.error("Get File:"+file+" Value Of CRC32 Error", e);
			return "";
		} 
	}

	/**
	 * 下载文件
	 * 
	 * @param url      服务器文件地址
	 * @param response
	 * @return
	 * 
	 *         downloadModelFile(){ var form=$("<form>");
	 *         form.attr("style","display:none"); form.attr("target","");
	 *         form.attr("method","post");
	 *         form.attr("action","./download-node-model");
	 *         $("body").append(form); form.submit(); }
	 */
	public static boolean downLoadFile(String url, HttpServletResponse response) {
		log.info(url);

		try {
			File file = new File(url); // 根据文件路径获得File文件
			// 设置文件类型(这样设置就不止是下Excel文件了，一举多得)
			if (url.endsWith("pdf")) {
				response.setContentType("application/pdf;charset=UTF-8");
			} else if (url.endsWith("csv")) {
				response.setContentType("application/msexcel;charset=UTF-8");
			} else if (url.endsWith("doc")) {
				response.setContentType("application/msword;charset=UTF-8");
			} else if (url.endsWith("xls")) {
				response.setContentType("application/msexcel;charset=UTF-8");
			} else if (url.endsWith("zip")) {
				response.setContentType("application/zip;charset=UTF-8");
			} else if (url.endsWith("cap") || url.endsWith("pcap")) {
				response.setContentType("application/vnd.tcpdump.pcap;charset=UTF-8");
			}
			// mine http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types

			// 文件名
			response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
			response.setContentLength((int) file.length());
			byte[] buffer = new byte[4096];// 缓冲区
			BufferedOutputStream output = null;
			BufferedInputStream input = null;
			try {
				output = new BufferedOutputStream(response.getOutputStream());
				input = new BufferedInputStream(new FileInputStream(file));
				int n = -1;
				// 遍历，开始下载
				while ((n = input.read(buffer, 0, 4096)) > -1) {
					output.write(buffer, 0, n);
				}
				output.flush(); // 不可少
				response.flushBuffer();// 不可少
			} catch (Exception e) {
				// 异常自己捕捉
			} finally {
				// 关闭流，不可少
				if (input != null)
					input.close();
				if (output != null)
					output.close();
			}
			return true;
		} catch (Exception e) {
			log.error("Download File "+url+" "+e.toString(), e);
		}
		return false;
	}

	/**
	 * 获取指定目录所在磁盘未使用率
	 * 
	 * @param file
	 * @return 未使用百分比整数
	 */
	public static int getPathFreeSpace(File file) {
		return (int) (file.getFreeSpace() * 100 / file.getTotalSpace());
	}

	/**
	 * 判断目录是否存在，不存在创建
	 * 
	 * @param path
	 */
	public static void checkAndMkdirPath(String path) {
		if (!new File(path).exists()) {
			new File(path).mkdirs();
		}
	}

	/**
	 * 更新文件
	 * 
	 * @param keyValue 替换关系
	 * @param file     旧文件
	 */
	public static boolean updateProperties(Map<String, String> keyValue, String file) {

		String tmpFile = file.replace(".properties", "-tmp.properties");

		String context = "";
		try(BufferedReader buf = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
				BufferedWriter write = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(tmpFile)));) {
			

			String[] tmpData;
			while ((context = buf.readLine()) != null) {

				if (context.contains("=")) {
					tmpData = context.split("\\=");

					if (keyValue.containsKey(tmpData[0].trim())) {
						if (tmpData.length == 2) {
							if (!tmpData[1].trim().equals(keyValue.get(tmpData[0].trim()))) { // 文件内容与设置内容不同
								context = tmpData[0].trim() + "=" + keyValue.get(tmpData[0].trim());
							}
						} else {
							context += keyValue.get(tmpData[0].trim());
						}
					}

				}
				write.write(context + "\n");
			}

		} catch (Exception e) {
			log.error("Edit File {} Error Of Context:{}", file, context);
			return false;
		}
		boolean result = moveFile(tmpFile,file);
		if (!result) {
			log.error("{} rename {} error", tmpFile, file);
		}

		return result;

	}

	/**
	 * 批量内容写入文件
	 * 
	 * @param dataList
	 * @param outputFile 输出
	 * @return
	 */
	public static boolean createDataFile(List<String> dataList, String outputFile) {
		String tmpEnd = ".tmp";

		File file = new File(outputFile + tmpEnd);

		try(BufferedWriter write = new BufferedWriter(new FileWriter(file))) {
			
			int num = 0;
			for (String data : dataList) {
				if (num > 0) {
					write.write(newLine);
				}
				write.write(data);
				num++;
			}
		} catch (Exception e) {
			log.error("Write File:" + file.toString() + " Error", e);
		}

		// 最后一个文件重命名加END
		if (!file.renameTo(new File(outputFile))) {
			log.error("{} To Rename {} Error", file.toString(), outputFile);
			return false;
		}
		log.info("Success Create File:{}", outputFile);
		return true;
	}

	/**
	 * 生成文件覆盖式写入
	 * 
	 * @param fileName   文件名
	 * @param title      文件标题
	 * @param dataList   数据
	 * @param output输出地址
	 * @return
	 */
	public static boolean createDataFile(String fileName, String title, List<String> dataList, String output) {

		String tmpEnd = ".tmp";
		String end = "_END.";
		long fileSize = 50 * 1024 * 1024; // 单个文件最大大小

		int index = 1;
		String name = fileName.replace("{index}", StringUtil.getFileIndex(index));
		File file = new File(output + File.separator + name + tmpEnd);
		BufferedWriter write = null;
		boolean result;
		File tmp;

		try {
			write = new BufferedWriter(new FileWriter(file));
			write.write(title + newLine); // 添加标题
			for (String data : dataList) {
				write.write(data + newLine);

				if (file.length() >= fileSize) { // 判断文件大小
					write.flush();
					write.close();
					// 修改文件名
					tmp = new File(file.toString().replace(name + tmpEnd, name));
					if (tmp.exists()) {
						tmp.delete();
					}
					result = file.renameTo(tmp);
					if (!result) {
						log.error("Rename File:{} Delete .tmp Error", file);
						return false;
					}
					log.info("Create File:{}", tmp);

					index++;
					name = fileName.replace("{index}", StringUtil.getFileIndex(index));
					file = new File(output + File.separator + name + tmpEnd);
					write = new BufferedWriter(new FileWriter(file));
					write.write(title + newLine); // 添加标题
				}

			}
			write.flush();
			write.close();
		} catch (Exception e) {
			log.error(e.toString(), e);
		}

		File endFile = new File(output + File.separator + name.replace(".", end));
		if (endFile.exists()) {
			endFile.delete();
		}

		// 最后一个文件重命名加END
		if (!file.renameTo(endFile)) {
			log.error("split finish,rename " + index + " to add END failed!");
			return false;
		}
		log.info("Create File:{}", endFile.toString());
		return true;
	}
	
	/**
	 * 复制文件
	 * @param src 源文件
	 * @param dest 目标文件
	 * @return
	 */
	public static boolean copyFile(String src,String dest) {
		try(
			FileInputStream input = new FileInputStream(src);
			FileOutputStream output = new FileOutputStream(dest);
		){
			byte[] b = new byte[1024 * 5];
			int len;
			while ((len = input.read(b)) != -1) {
				output.write(b, 0, len);
			}
			
		}catch (Exception e) {
			log.error("Copy File: "+src+" To: "+dest+" Error",e);
			return false;
		}
		
		return true;
	}
	

	/**
	 * 复制整个文件夹内容
	 * 
	 * @param oldPath String 原文件路径
	 * @param newPath String 复制后路径
	 * @return boolean
	 */
	public static boolean copyFolder(String oldPath, String newPath) {
		try {
			(new File(newPath)).mkdirs(); // 如果文件夹不存在 则建立新文件夹
			File a = new File(oldPath);
			String[] file = a.list();
			File temp = null;
			for (int i = 0; i < file.length; i++) {
				if (oldPath.endsWith(File.separator)) {
					temp = new File(oldPath + file[i]);
				} else {
					temp = new File(oldPath + File.separator + file[i]);
				}

				if (temp.isFile()) {
					FileInputStream input = new FileInputStream(temp);
					FileOutputStream output = new FileOutputStream(newPath + "/" + (temp.getName()).toString());
					byte[] b = new byte[1024 * 5];
					int len;
					while ((len = input.read(b)) != -1) {
						output.write(b, 0, len);
					}
					output.flush();
					output.close();
					input.close();
				}
				if (temp.isDirectory()) {// 如果是子文件夹
					copyFolder(oldPath + "/" + file[i], newPath + "/" + file[i]);
				}
			}
		} catch (Exception e) {
			log.error(e.toString(), e);
			return false;
		}
		return true;
	}

	/**
	 * 获取文件最后修改时间
	 * 
	 * @param fileString
	 */
	public static void getFileEndTime(String fileString) {
		File file = new File(fileString);
		if (file.exists()) {
			long time = file.lastModified();
			SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

			Calendar cal = Calendar.getInstance();
			cal.setTimeInMillis(time);
			System.out.println(formatter.format(cal.getTime()));
		} else {
			System.out.println("No Found File");
		}

	}

	/**
	 * 文件最后修改时间是否小于设定值 return -1 小于 1 大于 0 等于
	 */
	public static int checkFileTime(String fileString) {
		String time = "2021-08-31 23:59:59";

		File file = new File(fileString);
		long timeLong = file.lastModified();
		SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

		Calendar cal = Calendar.getInstance();
		cal.setTimeInMillis(timeLong);
		String fileTime = formatter.format(cal.getTime());
		return fileTime.compareTo(time);
	}

	/**
	 * 删除指定目录下空文件夹
	 * 
	 * @param path
	 */
	public static void deleteDirctory(String path) {
		int num;
		do {
			List<File> list = new ArrayList<File>();
			visitAll(list, new File(path));
			System.out.println(list.size());
			num=removeNullFile(list);
		}while(num>0);
		
	}

	/**
	 * 递归获取目录下文件夹
	 * @param list
	 * @param root
	 * @return
	 */
	private static List<File> visitAll(List<File> list, File root) {
		File[] dirs = root.listFiles();
		if (dirs != null && dirs.length > 0) {
			for (int i = 0; i < dirs.length; i++) {
				if (dirs[i].isDirectory()) {
					list.add(dirs[i]);
				}
				visitAll(list, dirs[i]);
			}
		}
		return list;
	}

	/**
	 * 删除空的文件夹
	 * 
	 * @param list
	 */
	private static int removeNullFile(List<File> list) {
		int num = 0;
		for (int i = 0; i < list.size(); i++) {
			File temp = list.get(i);
			// 是目录且为空
			if (temp.isDirectory() && temp.listFiles().length <= 0) {
				temp.delete();
				num++;
			}
		}
		return num;
	}
	
	/**
	 * 线程安全写入，注意等待超时
	 * 
	 * @param file
	 * @param data
	 * @param state true追加 false 覆盖
	 * @return
	 */
	public static boolean writeFileSafety(String file, String data,boolean state) {
		return writeFileSafety(new File(file), data,state);
	}
	
	/**
	 * 线程安全追加内容，注意等待超时
	 * 
	 * @param file
	 * @param data
	 * @return
	 */
	public static boolean writeFileSafety(String file, String data) {
		return writeFileSafety(new File(file), data,true);
	}

	/**
	 * 线程安全写入，注意等待超时
	 * 
	 * @param file
	 * @param data
	 * @param state true追加 false 覆盖
	 * @return
	 */
	public static boolean writeFileSafety(File file, String data,boolean state) {
		FileLock lock=null;
		FileOutputStream out=null;
		FileChannel fileChannel=null;
		try {
			if (!file.exists())
				file.createNewFile();

			// 对该文件加锁
			out = new FileOutputStream(file, state);
			fileChannel = out.getChannel();
			while(true) {
				try {
					lock = fileChannel.tryLock(); // 阻塞等待获取锁
					break;
				}catch(Exception e) {
					Thread.sleep(100);
				}
				
			}
			out.write(data.toString().getBytes("utf-8"));  //写入数据
			
		} catch (Exception e) {
			log.error("Write Data To File:"+file.toString()+" Error Data:"+data,e);
			return false;
		}finally {
			if(lock!=null) {
				try {
					lock.release();
				} catch (IOException e) {
					log.error("Close "+file.toString()+" Lock Error",e);
				}
			}
			
			if(fileChannel!=null) {
				try {
					fileChannel.close();
				} catch (IOException e) {
					log.error("Close "+file.toString()+" Channel Error",e);
				}
			}
			
			if(out!=null) {
				try {
					out.close();
				} catch (IOException e) {
					log.error("Close "+file.toString()+" OutputStream Error",e);
				}
			}
		}

		return true;
	}
	
	/**
	 * 生成临时文件，程序结束后删除
	 * @return 文件绝对路径
	 */
    public static String createTmpFile(String content) {
         File xmlFile = null;
         PrintWriter writer = null;
        try {
            xmlFile  = File.createTempFile("generator",".xml");
            writer = new PrintWriter(xmlFile);
            writer.println(content);
            
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            
             if (writer != null) {
                  writer.close();
             }
             xmlFile.deleteOnExit();
        }
        return xmlFile.getAbsolutePath();
    }
    
	/**
	 * 按行读取内容同步修改并写入，解决源文件过大，批量读取后处理占用过多内存
	 * @param sourceFile 源文件
	 * @param outputFile 输出文件
	 * @return
	 */
	public static boolean decryptFile(String sourceFile,String outputFile) {
		
		String context,tmp=".tmp";
		String[] tmpData;
		
		try(BufferedWriter write=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outputFile+tmp,false),"utf-8"));
				BufferedReader buf=new BufferedReader(new InputStreamReader(new FileInputStream(sourceFile),"utf-8"));
				) {
			
			
			while((context=buf.readLine())!=null){

				//数据二次处理
				if(context.contains(",")) {
					tmpData=context.split("\\,");
					write.write(tmpData[0]+","+tmpData[1]+System.getProperty("line.separator"));
				}
			}
		} catch (Exception e) {
			log.error("Decrypt File : "+sourceFile+" Error",e);
			return false;
		}
		
		boolean state= FileUtil.moveFile(outputFile+tmp, outputFile);
		if(!state) {
			log.error("Rename File:{} move {} Error",outputFile+tmp,tmp);
			return false;
		}
		return true;
	}
	
	/**
	 * 字节数组方式读取文件内容
	 * @param file
	 * @return
	 */
    public static byte[] byteRead(String file) {
    	byte[] result=new byte[0];
    	FileInputStream fis = null;
		try {
			fis=new FileInputStream(file);	
			//开始读
			 byte[] b = new byte[1024 ];
             int len=0;
             while ((len = fis.read(b)) != -1) {
                 result=ByteUtil.byteCopy(result,b,len);
             }
             
		}catch (IOException e) {
			log.error(StringUtil.formatString("Read File:{}  Error",file),e);
		}finally {
			//流是空的时候不能关闭，否则会空指针异常 
			if(fis!=null) {
				try {
					fis.close();
				} catch (Exception e) {
					log.error(StringUtil.formatString("Close Read File:{}  Error",file),e);
				}
			}
		}
		return result;
    }
    
    /**
     * 字节数组覆盖写入文件内容
     * @param data 字节数组
     * @param file 文件
     * @return
     */
    public static boolean byteWrite(byte[] data,String file) {
    	FileOutputStream output =null;
    	try {
    		output = new FileOutputStream(file);
            output.write(data, 0, data.length);
             
		}catch (Exception e) {
			log.error(StringUtil.formatString("Write File:{}  Error",file),e);
			return false;
		}finally {
			if(output!=null) {
				try {
					output.flush();
					output.close();
				} catch (Exception e) {
					log.error(StringUtil.formatString("Close Write File:{}  Error",file),e);
				}
			}
			
		}
		return true;
    }
	
}
